<?php

/**
 * Handles application language selection
 *
 * @version 1.0
 */
class CMS_I18n_Language
{
    /**#@+
     * File extension constants
     */
    const RESOURCE_FILE_EXTENSION = '.mo';
    const RESOURCE_JS_FILE_EXTENSION = '.js';
    const LANGUAGE_CACHE_KEY = 'language';
    /**#@-*/

    /**
     * Translate configuration array
     * @var array
     */
    private $config;

    /**
     * Class constructor
     * Also generates js files for on client translation when needed
     *
     * @throws CMS_I18n_Exception
     * @param array $config
     */
    public function __construct($config)
    {
        $this->config = $config;
        if ($this->config['reload_language'])
            $this->updateJsLocales();
    }

    /**
     * Globaly sets the application language
     * Stores/reads translate object from memcache
     * 
     * @throws CMS_I18n_Exception
     * @param string $language
     */
    public function setApplicationLanguage($language)
    {
        $translate = $this->buildTranslate($language);

        Zend_Registry::set('Zend_Translate', $translate);
    }

    /**
     * Returns an instance of Zend_Translate
     * 
     * @param string $language
     * 
     * @return Zend_Translate
     */
    private function buildTranslate($language)
    {
        $localesDir = $this->config['locales_directory'];
        return new Zend_Translate(
                'gettext',
                $localesDir . DIRECTORY_SEPARATOR . $language . self::RESOURCE_FILE_EXTENSION,
                $language,
                array('disableNotices' => true)
        );
    }

    /**
     * Loops over locales directory to regenerate language files
     */
    private function updateJsLocales()
    {
        $sourceFilePattern = "/^.." . self::RESOURCE_FILE_EXTENSION . "$/";
        $localesDir = $this->config['locales_directory'];
        $dirHandler = @opendir($localesDir);
        if ($dirHandler === false)
            throw new CMS_I18n_Exception("Couldn't open directory",
                CMS_I18n_Exception::CAN_NOT_OPEN_DIRECTORY,
                    CMS_Exception::LEVEL_CRIT);

        while (false !== ($file = readdir($dirHandler)))
        {
            if (filetype($localesDir . DIRECTORY_SEPARATOR . $file) === 'file' &&
                    preg_match($sourceFilePattern, $file) > 0)
            {
                $locale = new Zend_Locale(str_replace(self::RESOURCE_FILE_EXTENSION, "", $file));
                $translate = new Zend_Translate(
                        'gettext',
                        $localesDir . DIRECTORY_SEPARATOR . $file,
                        $locale,
                        array('disableNotices' => true)
                );
                $this->generateJsLocale($translate);
            }
        }
    }

    /**
     * Generates js language file for a locale
     *
     * @param Zend_Translate $translate
     */
    private function generateJsLocale(Zend_Translate $translate)
    {
        $locale = $translate->getLocale();
        $jsFileName = $locale . self::RESOURCE_JS_FILE_EXTENSION;
        $jsPattern = '/^JS_(.*)$/';

        $messages = $translate->getMessages();
        $jsMessages = array();
        foreach ($messages as $key => $value)
        {
            if (preg_match($jsPattern, $key) == 0)
                continue;

            $jsMessages[$key] = $value;
        }
        $json = Zend_Json::encode($jsMessages);
        $jsContent = 'if(typeof I18n.' . $locale . ' == "undefined") {';
        $jsContent .= "\n  I18n." . $locale . ' = ';
        $jsContent .= $json;
        $jsContent .= "\n;";
        $jsContent .= "\nI18n.locale = \"" . $locale . '";';
        $jsContent .= "\n}\n";

        @$result = file_put_contents(
                $this->config['js_locales_directory'] .
                DIRECTORY_SEPARATOR .
                $jsFileName,
                $jsContent
        );

        if ($result === false)
            throw new CMS_I18n_Exception("Couldn't write js resource file to disk",
                CMS_I18n_Exception::CAN_NOT_WRITE_FILE, CMS_Exception::LEVEL_CRIT);
    }
}
